home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 September / PCWorld_2002-09_cd.bin / Software / Vyzkuste / httrack / httrack-3.20RC4.exe / {app} / src / htsname.c < prev    next >
C/C++ Source or Header  |  2002-07-09  |  42KB  |  1,248 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       savename routine (compute output filename)             */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. #include "htsname.h"
  39.  
  40. /* specific definitions */
  41. #include "htsbase.h"
  42. #include "htstools.h"
  43. #include "htsmd5.h"
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <ctype.h>
  47. /* END specific definitions */
  48.  
  49. #undef test_flush
  50. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  51.  
  52. #define ADD_STANDARD_PATH \
  53.     {  /* ajout nom */\
  54.       char buff[HTS_URLMAXSIZE*2];\
  55.       buff[0]='\0';\
  56.       strncat(buff,start_pos,(int) (nom_pos - start_pos));\
  57.       url_savename_addstr(save,buff);\
  58.     }
  59.  
  60. #define ADD_STANDARD_NAME(shortname) \
  61.     {  /* ajout nom */\
  62.       char buff[HTS_URLMAXSIZE*2];\
  63.       standard_name(buff,dot_pos,nom_pos,fil_complete,(shortname));\
  64.       url_savename_addstr(save,buff);\
  65.     }
  66.  
  67.  
  68. /* Avoid stupid DOS system folders/file such as 'nul' */
  69. /* Based on linux/fs/umsdos/mangle.c */
  70. static const char *hts_tbdev[] =
  71. {
  72.     "/prn", "/con", "/aux", "/nul",
  73.     "/lpt1", "/lpt2", "/lpt3", "/lpt4",
  74.     "/com1", "/com2", "/com3", "/com4",
  75.     "/clock$",
  76.     "/emmxxxx0", "/xmsxxxx0", "/setverxx",
  77.     ""
  78. };
  79.  
  80.  
  81.  
  82. // forme le nom du fichier α sauver (save) α partir de fil et adr
  83. // systΦme intelligent, qui renomme en cas de besoin (exemple: deux INDEX.HTML et index.html)
  84. int url_savename(char* adr_complete,char* fil_complete,char* save,char* former_adr,char* former_fil,char* referer_adr,char* referer_fil,httrackp* opt,lien_url** liens,int lien_tot,lien_back* back,int back_max,cache_back* cache,hash_struct* hash,int ptr,int numero_passe) {
  85.   char newfil[HTS_URLMAXSIZE*2];   /* ="" */
  86.   char* fil;
  87.   char* adr;
  88.   char* print_adr;
  89.   char *start_pos=NULL,*nom_pos=NULL,*dot_pos=NULL;  // Position nom et point
  90.   // pour changement d'extension ou de nom (content-disposition)
  91.   int ext_chg=0;
  92.   char ext[256];
  93.   int max_char=0;
  94.   //CLEAR
  95.   newfil[0]=ext[0]='\0';
  96.  
  97.   /* 8-3 ? */
  98.   switch(opt->savename_83) {
  99.   case 1:
  100.     max_char=8;
  101.     break;
  102.   case 2:
  103.     max_char=30;
  104.     break;
  105.   default:
  106.     max_char=8;
  107.     break;
  108.   }
  109.  
  110.   // effacer save
  111.   save[0]='\0';
  112.   // fil
  113.   fil = fil_complete;
  114.   // et adr (sauter user/pass)
  115.   // on prend le parti de mettre les fichiers avec login/pass au mΩme endroit que si ils
  116.   // Θtaient capturΘs sans ces paramΦtres
  117.   // c'est pour cette raison qu'on ignore totalement adr_complete (mΩme pour la recherche en table de hachage)
  118.   adr=jump_identification(adr_complete);
  119.  
  120.   // α afficher sans ftp://
  121.   print_adr=jump_protocol(adr);
  122.  
  123.   // court-circuit pour lien primaire
  124.   if (strnotempty(adr)==0) {
  125.     if (strcmp(fil,"primary")==0) {
  126.       strcat(save,"primary.html");
  127.       return 0;
  128.     }
  129.   }
  130.  
  131.  
  132.   // vΘrifier que le nom n'a pas dΘja ΘtΘ calculΘ (si oui le renvoyer tel que)
  133.   // vΘrifier que le nom n'est pas dΘja pris...
  134.   // NOTE: si on cherche /toto/ et que /toto est trouvΘ on le prend (et rΘciproquqment) ** // **
  135.   if (liens!=NULL) { 
  136.     int i;
  137.  
  138. #if HTS_HASH
  139.     i=hash_read(hash,adr,fil_complete,1);      // recherche table 1 (adr+fil)
  140.     if (i>=0) {    // ok, trouvΘ
  141.       strcpy(save,liens[i]->sav);
  142.       return 0;
  143.     }
  144.     i=hash_read(hash,adr,fil_complete,2);      // recherche table 2 (former_adr+former_fil)
  145.     if (i>=0) {    // ok, trouvΘ
  146.       // copier location moved!
  147.       strcpy(adr_complete,liens[i]->adr);
  148.       strcpy(fil_complete,liens[i]->fil);
  149.       // et save
  150.       strcpy(save,liens[i]->sav);  // copier (formΘ α partir du nouveau lien!)
  151.       return 0;
  152.     }
  153. #else
  154.     for(i=lien_tot-1;i>=0;i--) {        
  155. #if HTS_CASSE
  156.       if ((strcmp(liens[i]->adr,adr)==0) && (strcmp(liens[i]->fil,fil_complete)==0))
  157. #else
  158.       if ((strfield2(liens[i]->adr,adr)) && (strfield2(liens[i]->fil,fil_complete)))
  159. #endif
  160.       {    // ok c'est le mΩme lien, adresse dΘja dΘfinie
  161.         strcpy(save,liens[i]->sav);
  162.         return 0;
  163.       }
  164.       if (liens[i]->former_adr) {     // tester ancienne loc?
  165. #if HTS_CASSE
  166.         if ((strcmp(liens[i]->former_adr,adr)==0) && (strcmp(liens[i]->former_fil,fil_complete)==0))
  167. #else
  168.         if ((strfield2(liens[i]->former_adr,adr)) && (strfield2(liens[i]->former_fil,fil_complete)))
  169. #endif
  170.         {
  171.           // copier location moved!
  172.           strcpy(adr_complete,liens[i]->adr);
  173.           strcpy(fil_complete,liens[i]->fil);
  174.           // et save
  175.           strcpy(save,liens[i]->sav);  // copier (formΘ α partir du nouveau lien!)
  176.           return 0;
  177.         }
  178.       }
  179.     }
  180. #endif
  181.  
  182.     // chercher sans / ou avec / dans former
  183.     {
  184.       char fil_complete_patche[HTS_URLMAXSIZE*2];
  185.       strcpy(fil_complete_patche,fil_complete);
  186.       // Version avec ou sans /
  187.       if (fil_complete_patche[strlen(fil_complete_patche)-1]=='/')
  188.         fil_complete_patche[strlen(fil_complete_patche)-1]='\0';
  189.       else
  190.         strcat(fil_complete_patche,"/");
  191. #if HTS_HASH
  192.       i=hash_read(hash,adr,fil_complete_patche,2);      // recherche table 2 (former_adr+former_fil)
  193.       if (i>=0) {
  194.         // Θcraser fil et adr (pas former_fil?????)
  195.         strcpy(adr_complete,liens[i]->adr);
  196.         strcpy(fil_complete,liens[i]->fil);
  197.         // Θcrire save
  198.         strcpy(save,liens[i]->sav);
  199.         return 0;
  200.       }
  201. #else
  202.       // mΩme boucle en gros
  203.       for(i=lien_tot-1;i>=0;i--) {        
  204.         if (liens[i]->former_adr) {    // former-adr?
  205. #if HTS_CASSE
  206.           if ((strcmp(liens[i]->former_adr,adr)==0) && (strcmp(liens[i]->former_fil,fil_complete_patche)==0))
  207. #else
  208.           if ((strfield2(liens[i]->former_adr,adr)) && (strfield2(liens[i]->former_fil,fil_complete_patche)))
  209. #endif
  210.           {    // ok c'est le mΩme lien, adresse dΘja dΘfinie
  211.             // Θcraser fil et adr (pas former_fil?????)
  212.             strcpy(adr_complete,liens[i]->adr);
  213.             strcpy(fil_complete,liens[i]->fil);
  214.             // Θcrire save
  215.             strcpy(save,liens[i]->sav);
  216.             return 0;
  217.           }
  218.         }
  219.       }
  220. #endif
  221.     }
  222.   }
  223.  
  224.   // vΘrifier la non prΘsence de paramΦtres dans le nom de fichier
  225.   // si il y en a, les supprimer (ex: truc.cgi?subj=aspirateur)
  226.   // nΘanmoins, gardΘ pour vΘrifier la non duplication (voir aprΦs)
  227.   {
  228.     char* a;
  229.     a=strchr(fil,'?');
  230.     if (a!=NULL) {
  231.       strncat(newfil,fil,(int) (a - fil));
  232.     } else {
  233.       strcpy(newfil,fil);
  234.     }
  235.     fil=newfil;
  236.   }
  237.   // dΘcoder %
  238.   strcpy(fil,unescape_http(fil));
  239.   /*
  240.   {
  241.     char tempo[HTS_URLMAXSIZE*2];
  242.     int i,j=0;
  243.     for (i=0;i<(int) strlen(fil);i++) {
  244.       if (fil[i]=='%') {
  245.         i++;
  246.         tempo[j++]=(char) ehex(fil+i);
  247.         i++;    // sauter 2 caractΦres finalement
  248.       } else
  249.         tempo[j++]=fil[i];
  250.     }
  251.     tempo[j++]='\0';
  252.     strcpy(fil,tempo);
  253.   }
  254.   */
  255.   
  256.   
  257.   /* replace shtml to html.. */
  258.   switch (ishtml(fil)) {       /* .html,.shtml,.. */
  259.   case 1:
  260.     if ( 
  261.       (strcmp(get_ext(fil),"html") != 0)
  262.       && (strcmp(get_ext(fil),"htm") != 0)
  263.       ) {
  264.       strcpy(ext,"html");
  265.       ext_chg=1;
  266.     }
  267.     break;
  268.     case 0:
  269.       if (!strnotempty(ext)) {
  270.         if (is_userknowntype(get_ext(fil))) {      // mime known by user
  271.           char mime[1024];
  272.           mime[0]=ext[0]='\0';
  273.           get_userhttptype(0,mime,get_ext(fil));
  274.           if (strnotempty(mime)) {
  275.             give_mimext(ext,mime);
  276.             if (strnotempty(ext)) {
  277.               ext_chg=1;
  278.             }
  279.           }
  280.         }
  281.       }
  282.       break;
  283.   }
  284.   
  285.  
  286.   // si option check_type activΘe
  287.   if ((opt->check_type) && (!ext_chg)) {
  288.     if ( (!strfield(adr_complete,"file://")) 
  289.       && (!strfield(adr_complete,"ftp://")) 
  290.       ) {
  291.       // tester type avec requΦte HEAD si on ne connait pas le type du fichier
  292.       if (!(   (opt->check_type==1) && (fil[strlen(fil)-1]=='/')   ))    // slash doit Ωtre html?
  293.       if (ishtml(fil)<0) { // on ne sait pas si c'est un html ou un fichier..
  294.         // lire dans le cache
  295.         htsblk r = cache_read(opt,cache,adr,fil,NULL);              // test uniquement
  296.         if (r.statuscode != -1) {  // pas d'erreur de lecture cache
  297.           char s[16]; s[0]='\0';
  298.           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  299.             fspc(opt->log,"debug"); fprintf(opt->log,"Testing link type (from cache) %s%s"LF,adr_complete,fil_complete);
  300.             test_flush;
  301.           }
  302.           if (strnotempty(r.cdispo)) {        /* filename given */
  303.             ext_chg=2;      /* change filename */
  304.             strcpy(ext,r.cdispo);
  305.           }
  306.           else if (!may_unknown(r.contenttype)) {  // on peut patcher α priori?
  307.             give_mimext(s,r.contenttype);  // obtenir extension
  308.             if (strnotempty(s)>0) {        // on a reconnu l'extension
  309.               ext_chg=1;
  310.               strcpy(ext,s);
  311.             }
  312.           }
  313.           //
  314.         } else {          // test imposible dans le cache, faire une requΩte
  315.           //
  316. #if HTS_ANALYSTE
  317.           int hihp=_hts_in_html_parsing;
  318. #endif
  319.           int has_been_moved=0;
  320.           char curr_adr[HTS_URLMAXSIZE*2],curr_fil[HTS_URLMAXSIZE*2];
  321.           curr_adr[0]=curr_fil[0]='\0';
  322. #if HTS_ANALYSTE
  323.           _hts_in_html_parsing=2;  // test
  324. #endif
  325.           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  326.             fspc(opt->log,"debug"); fprintf(opt->log,"Testing link type %s%s"LF,adr_complete,fil_complete);
  327.             test_flush;
  328.           }
  329.           strcpy(curr_adr,adr_complete);
  330.           strcpy(curr_fil,fil_complete);
  331.           // ajouter dans le backing le fichier en mode test
  332.           // savename: rien car en mode test
  333.           if (back_add(back,back_max,opt,cache,curr_adr,curr_fil,BACK_ADD_TEST,referer_adr,referer_fil,1,NULL)!=-1) {
  334.             int b;
  335.             b=back_index(back,back_max,curr_adr,curr_fil,BACK_ADD_TEST);         
  336.             if (b>=0) {
  337.               int petits_tours=0;
  338.               int get_test_request=0;       // en cas de bouclage sur soi mΩme avec HEAD, tester avec GET.. parfois c'est la cause des problΦmes
  339.               do {
  340.                 // temps α attendre, et remplir autant que l'on peut le cache (backing)
  341.                 if (back[b].status>0) back_wait(back,back_max,opt,cache,0);        
  342.                 if (ptr>=0)
  343.                   back_fillmax(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
  344.   
  345.                 // on est obligΘ d'appeler le shell pour le refresh..
  346. #if HTS_ANALYSTE
  347.                 {
  348.                   
  349.                   // Transfer rate
  350.                   engine_stats();
  351.                   
  352.                   // Refresh various stats
  353.                   HTS_STAT.stat_nsocket=back_nsoc(back,back_max);
  354.                   HTS_STAT.stat_errors=fspc(NULL,"error");
  355.                   HTS_STAT.stat_warnings=fspc(NULL,"warning");
  356.                   HTS_STAT.stat_infos=fspc(NULL,"info");
  357.                   HTS_STAT.nbk=backlinks_done(liens,lien_tot,ptr);
  358.                   HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
  359.  
  360.                   if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) {
  361.                     return -1;
  362.                   } else if (_hts_cancel) {    // cancel 2 ou 1 (cancel parsing)
  363.                     back_delete(back,b);       // cancel test
  364.                   }
  365.                 }
  366. #endif
  367.                 
  368.                 
  369.                 // traitement des 304,303..
  370.                 if (back[b].status<=0) {
  371.                   if (    (back[b].r.statuscode==301)
  372.                        || (back[b].r.statuscode==302)
  373.                        || (back[b].r.statuscode==303)
  374.                        || (back[b].r.statuscode==307)
  375.                      ) {    // agh moved.. un tit tour de plus
  376.                     if ((petits_tours<5) && (former_adr) && (former_fil)) { // on va pas tourner en rond non plus!
  377.                       if ((int) strnotempty(back[b].r.location)) {    // location existe!
  378.                         char mov_url[HTS_URLMAXSIZE*2],mov_adr[HTS_URLMAXSIZE*2],mov_fil[HTS_URLMAXSIZE*2];
  379.                         mov_url[0]=mov_adr[0]=mov_fil[0]='\0';
  380.                         //
  381.                         strcpy(mov_url,back[b].r.location);    // copier URL
  382.                         if (ident_url_relatif(mov_url,curr_adr,curr_fil,mov_adr,mov_fil)>=0) {                        
  383.                           // si non bouclage sur soi mΩme, ou si test avec GET non testΘ
  384.                           if ((strcmp(mov_adr,curr_adr)) || (strcmp(mov_fil,curr_fil)) || (get_test_request==0)) {
  385.                             // bouclage?
  386.                             if ((!strcmp(mov_adr,curr_adr)) && (!strcmp(mov_fil,curr_fil)))
  387.                               get_test_request=1;     // faire requΦte avec GET
  388.  
  389.                             // recopier former_adr/fil?
  390.                             if ((former_adr) && (former_fil)) {
  391.                               if (strnotempty(former_adr)==0) {    // Pas dΘja notΘ
  392.                                 strcpy(former_adr,curr_adr);
  393.                                 strcpy(former_fil,curr_fil);
  394.                               }
  395.                             }
  396.  
  397.                             // ftp: stop!
  398.                             if (strfield(mov_url,"ftp://")) {    // ftp, ok on arrΩte
  399.                               has_been_moved = 1;
  400.                               back_delete(back,b);    // ok
  401.                               strcpy(curr_adr,mov_adr);
  402.                               strcpy(curr_fil,mov_fil);
  403.                             } else {
  404.                               char* methode;
  405.                               if (!get_test_request)
  406.                                 methode=BACK_ADD_TEST;      // tester avec HEAD
  407.                               else {
  408.                                 methode=BACK_ADD_TEST2;     // tester avec GET
  409.                                 if ( opt->errlog!=NULL ) {
  410.                                   fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Loop with HEAD request (during prefetch) at %s%s"LF,curr_adr,curr_fil);
  411.                                   test_flush;
  412.                                 }                    
  413.                               }
  414.                               // Ajouter
  415.                               if (back_add(back,back_max,opt,cache,mov_adr,mov_fil,methode,referer_adr,referer_fil,1,NULL)!=-1) {    // OK
  416.                                 if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  417.                                   fspc(opt->errlog,"warning"); fprintf(opt->errlog,"(during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil);
  418.                                   test_flush;
  419.                                 }                    
  420.                                 
  421.                                 // libΘrer emplacement backing actuel et attendre le prochain
  422.                                 back_delete(back,b);
  423.                                 strcpy(curr_adr,mov_adr);
  424.                                 strcpy(curr_fil,mov_fil);
  425.                                 b=back_index(back,back_max,curr_adr,curr_fil,methode);         
  426.                                 if (!get_test_request)
  427.                                   has_been_moved = 1;       // sinon ne pas forcer has_been_moved car non dΘplacΘ
  428.                                 petits_tours++;
  429.                                 //
  430.                               } else {// sinon on fait rien et on s'en va.. (ftp etc)
  431.                                 if ( (opt->debug>1)  && (opt->errlog)) {
  432.                                   fspc(opt->errlog,"debug"); fprintf(opt->errlog,"Warning: Savename redirect backing error at %s%s"LF,mov_adr,mov_fil);
  433.                                   test_flush;
  434.                                 } 
  435.                               }
  436.                             }
  437.                           } else {
  438.                             if ( opt->errlog!=NULL ) {
  439.                               fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Unable to test %s%s (loop to same filename)"LF,adr_complete,fil_complete);
  440.                               test_flush;
  441.                             }
  442.                           }
  443.                           
  444.                         }
  445.                       }
  446.                     } else{  // arrΩter les frais
  447.                       if ( opt->errlog!=NULL ) {
  448.                         fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Unable to test %s%s (loop)"LF,adr_complete,fil_complete);
  449.                         test_flush;
  450.                       }
  451.                     }
  452.                   }  // ok, leaving
  453.                 }
  454.                 
  455.               } while(back[b].status>0);
  456.               
  457.               // Si non dΘplacΘ, forcer type?
  458.               if (!has_been_moved) {
  459.                 if (back[b].r.statuscode!=-10) {    // erreur
  460.                   if (strnotempty(back[b].r.contenttype)==0)
  461.                     strcpy(back[b].r.contenttype,"text/html");    // message d'erreur en html
  462.                   // Finalement on, renvoie un erreur, pour ne toucher α rien dans le code
  463.                   // libΘrer emplacement backing
  464.                   /*if (opt->errlog!=NULL) {
  465.                     fspc(opt->errlog,0); fprintf(opt->errlog,"Error: (during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil);
  466.                     test_flush;
  467.                   }                    
  468.                   back_delete(back,b);
  469.                   return -1;        // ERREUR (404 par exemple)
  470.                   */
  471.                 } 
  472.                 
  473.                 {            // pas d'erreur, changer type?
  474.                   char s[16];
  475.                   s[0]='\0';
  476.                   if (strnotempty(back[b].r.cdispo)) {        /* filename given */
  477.                     ext_chg=2;      /* change filename */
  478.                     strcpy(ext,back[b].r.cdispo);
  479.                   }
  480.                   else if ((!may_unknown(back[b].r.contenttype)) || (!get_ext(back[b].url_fil)) ) {  // on peut patcher α priori? (pas interdit ou pas de type)
  481.                     give_mimext(s,back[b].r.contenttype);  // obtenir extension
  482.                     if (strnotempty(s)>0) {    // on a reconnu l'extension
  483.                       ext_chg=1;
  484.                       strcpy(ext,s);
  485.                     }
  486.                   }
  487.                 }
  488.               }
  489.               // FIN Si non dΘplacΘ, forcer type?
  490.  
  491.               // libΘrer emplacement backing
  492.               back_delete(back,b);
  493.               
  494.               // --- --- ---
  495.               // oops, a ΘtΘ dΘplacΘ.. on recalcule en rΘcursif (osons!)
  496.               if (has_been_moved) {
  497.                 // copier adr, fil (optionnel, mais sinon marche pas pour le rip)
  498.                 strcpy(adr_complete,curr_adr);
  499.                 strcpy(fil_complete,curr_fil);
  500.                 // copier adr, fil
  501.                 
  502.                 return url_savename(curr_adr,curr_fil,save,NULL,NULL,referer_adr,referer_fil,opt,liens,lien_tot,back,back_max,cache,hash,ptr,numero_passe);
  503.               }
  504.               // --- --- ---
  505.               
  506.             }
  507.             
  508.           } else {
  509.             printf("PANIC! : Savename Crash adding error, unexpected error found.. [%d]\n",__LINE__);
  510. #if BDEBUG==1
  511.             printf("error while savename crash adding\n");
  512. #endif
  513.             if (opt->errlog) {
  514.               fspc(opt->errlog,"error"); fprintf(opt->errlog,"Unexpected savename backing error at %s%s"LF,adr,fil_complete);
  515.               test_flush;
  516.             } 
  517.             
  518.           }
  519.           // restaurer
  520. #if HTS_ANALYSTE
  521.           _hts_in_html_parsing=hihp;
  522. #endif
  523.         }  // cachΘ?
  524.       }
  525.     }
  526.   }
  527.  
  528.  
  529.  
  530.   // - - - DEBUT NOMMAGE - - -
  531.  
  532.   // Donner nom par dΘfaut?
  533.   if (fil[strlen(fil)-1]=='/')  {
  534.     if (!strfield(adr_complete,"ftp://"))
  535.       strcat(fil,DEFAULT_HTML);     // nommer page par dΘfaut!!
  536.     else {
  537.       if (!opt->proxy.active)
  538.         strcat(fil,DEFAULT_FTP);     // nommer page par dΘfaut (texte)
  539.       else
  540.         strcat(fil,DEFAULT_HTML);     // nommer page par dΘfaut (α priori ici html depuis un proxy http)
  541.     }
  542.   }
  543.   // Changer extension?
  544.   // par exemple, php3 sera sauvΘ en html, cgi en html ou gif, xbm etc.. selon les cas
  545.   if (ext_chg) {  // changer ext
  546.     char* a=fil+strlen(fil)-1;
  547.     if ( (opt->debug>1) && (opt->log!=NULL) ) {
  548.       fspc(opt->log,"debug");
  549.       if (ext_chg==1)
  550.         fprintf(opt->log,"Changing link extension %s%s to .%s"LF,adr_complete,fil_complete,ext);
  551.       else
  552.         fprintf(opt->log,"Changing link name %s%s to %s"LF,adr_complete,fil_complete,ext);
  553.       test_flush;
  554.     }
  555.     if (ext_chg==1) {
  556.       while((a > fil) && (*a!='.') && (*a!='/')) a--;
  557.       if (*a=='.') *a='\0';  // couper
  558.       strcat(fil,".");      // recopier point
  559.     } else {
  560.       while(( a > fil) && (*a!='/')) a--;
  561.       if (*a=='/') a++;
  562.       *a='\0';
  563.    }
  564.     strcat(fil,ext);    // copier ext/nom
  565.   }
  566.  
  567.   // Rechercher premier / et dernier .
  568.   {  
  569.     char* a=fil+strlen(fil)-1;
  570.  
  571.     // passer structures
  572.     start_pos=fil;
  573.     while(( a > fil) && (*a != '/') && (*a != '\\')) {
  574.       if (*a == '.')    // point? noter position
  575.         if (!dot_pos)
  576.           dot_pos=a;
  577.         a--;
  578.     }
  579.     if ((*a=='/') || (*a=='\\')) a++;
  580.     nom_pos = a;
  581.   }
  582.  
  583.   
  584.   // un nom de fichier est gΘnΘrΘ
  585.   // s'il existe dΘja, alors on le mofifie lΘgΦrement
  586.  
  587.   // ajouter nom du site Θventuellement en premier
  588.   if (opt->savename_type == -1) {    // utiliser savename_userdef! (%h%p/%n%q.%t)
  589.     char* a = opt->savename_userdef;
  590.     char* b = save;
  591.     /*char *nom_pos=NULL,*dot_pos=NULL;  // Position nom et point */
  592.     char tok;
  593.  
  594.     /*
  595.     {  // Rechercher premier /
  596.       char* a=fil+strlen(fil)-1;
  597.       // passer structures
  598.       while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) {
  599.         if (*a == '.')    // point? noter position
  600.         if (!dot_pos)
  601.           dot_pos=a;
  602.         a--;
  603.       }
  604.       if ((*a=='/') || (*a=='\\')) a++;
  605.       nom_pos = a;
  606.     }
  607.     */
  608.  
  609.     // Construire nom
  610.     while ((*a) && (((int) (b - save)) < HTS_URLMAXSIZE ) ) {    // parser, et pas trop long..
  611.       if (*a == '%') {
  612.         int short_ver=0;
  613.         a++;
  614.         if (*a == 's') {
  615.           short_ver=1;
  616.           a++;
  617.         }
  618.         *b='\0';
  619.         switch(tok=*a++) {
  620.           case '[':            // %[param]
  621.             if (strchr(a,']')) {
  622.               char name[256];
  623.               char* c=name;
  624.               while(*a!=']') {
  625.                 *c++=*a++;
  626.               }
  627.               a++;
  628.               *c++='\0';
  629.               strcat(name,"=");           /* param=.. */
  630.               c=strchr(fil_complete,'?');
  631.               /* parameters exists */
  632.               if (c) {
  633.                 c=strstr(c,name);     /* finds param= */
  634.                 if (c) {
  635.                   c+=strlen(name);    /* jumps "param=" */
  636.                   while( (*c) && (*c!='&'))
  637.                     *b++=*c++;
  638.                 }
  639.               }
  640.             }
  641.           break;
  642.           case '%': *b++='%'; break;
  643.           case 'n':    // nom sans ext
  644.             if (dot_pos) {
  645.               if (!short_ver)    // Noms longs
  646.                 strncat(b,nom_pos,(int) (dot_pos - nom_pos));
  647.               else
  648.                 strncat(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  649.             } else {
  650.               if (!short_ver)    // Noms longs
  651.                 strcpy(b,nom_pos);
  652.               else
  653.                 strncat(b,nom_pos,8);
  654.             }
  655.             b+=strlen(b);   // pointer α la fin
  656.             break;
  657.           case 'N':    // nom avec ext
  658.             // RECOPIE NOM + EXT
  659.             *b='\0';
  660.             if (dot_pos) {
  661.               if (!short_ver)    // Noms longs
  662.                 strncat(b,nom_pos,(int) (dot_pos - nom_pos));
  663.               else
  664.                 strncat(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  665.             } else {
  666.               if (!short_ver)    // Noms longs
  667.                 strcpy(b,nom_pos);
  668.               else
  669.                 strncat(b,nom_pos,8);
  670.             }
  671.             b+=strlen(b);   // pointer α la fin
  672.             // RECOPIE NOM + EXT
  673.             *b='\0';
  674.             if (dot_pos) {
  675.               if (!short_ver)    // Noms longs
  676.                 strcpy(b,dot_pos+1);
  677.               else
  678.                 strncat(b,dot_pos+1,3);
  679.             } else {
  680.               if (!short_ver)    // Noms longs
  681.                 strcpy(b,DEFAULT_EXT);    // pas de..
  682.               else
  683.                 strcpy(b,DEFAULT_EXT_SHORT);    // pas de..
  684.             }
  685.             b+=strlen(b);   // pointer α la fin
  686.             //
  687.             break;
  688.           case 't':    // ext
  689.             *b='\0';
  690.             if (dot_pos) {
  691.               if (!short_ver)    // Noms longs
  692.                 strcpy(b,dot_pos+1);
  693.               else
  694.                 strncat(b,dot_pos+1,3);
  695.             } else {
  696.               if (!short_ver)    // Noms longs
  697.                 strcpy(b,DEFAULT_EXT);    // pas de..
  698.               else
  699.                 strcpy(b,DEFAULT_EXT_SHORT);    // pas de..
  700.             }
  701.             b+=strlen(b);   // pointer α la fin
  702.             break;
  703.           case 'p':    // path sans dernier /
  704.             *b='\0';
  705.             if (nom_pos != fil + 1) { // pas: /index.html (chemin nul)
  706.               if (!short_ver) {   // Noms longs
  707.                 strncat(b,fil,(int) (nom_pos - fil) - 1);
  708.               } else {
  709.                 char pth[HTS_URLMAXSIZE*2],n83[HTS_URLMAXSIZE*2];
  710.                 pth[0]=n83[0]='\0';
  711.                 //
  712.                 strncat(pth,fil,(int) (nom_pos - fil) - 1);
  713.                 long_to_83(opt->savename_83,n83,pth);
  714.                 strcpy(b,n83);
  715.               }
  716.             }
  717.             b+=strlen(b);   // pointer α la fin
  718.             break;
  719.           case 'h':    // host
  720.             *b='\0';
  721.             if (strcmp(adr_complete,"file://")==0) {
  722.               if (!short_ver)    // Noms longs
  723.                 strcpy(b,"localhost");
  724.               else
  725.                 strcpy(b,"local");
  726.             } else {
  727.               if (!short_ver)    // Noms longs
  728.                 strcpy(b,print_adr);
  729.               else
  730.                 strncat(b,print_adr,8);
  731.             }
  732.             b+=strlen(b);   // pointer α la fin
  733.             break;
  734.           case 'M':         /* host/address?query MD5 (128-bits) */
  735.             *b='\0';
  736.             {
  737.               char digest[32+2];
  738.               char buff[HTS_URLMAXSIZE*2];
  739.               digest[0]=buff[0]='\0';
  740.               strcpy(buff,adr);
  741.               strcat(buff,fil_complete);
  742.               domd5mem(buff,strlen(buff),digest,1,0);
  743.               strcpy(b,digest);
  744.             }
  745.             b+=strlen(b);   // pointer α la fin
  746.             break;
  747.           case 'Q': case 'q':         /* query MD5 (128-bits/16-bits) 
  748.                                          GENERATED ONLY IF query string exists! */
  749.             *b='\0';
  750.             strncat(b,url_md5(fil_complete),(tok == 'Q')?32:4);
  751.             b+=strlen(b);   // pointer α la fin
  752.             break;
  753.         }
  754.       } else
  755.         *b++=*a++;
  756.     }
  757.     *b++='\0';
  758.     //
  759.     // Types prΘdΘfinis
  760.     //
  761.  
  762.   } 
  763.   //
  764.   // Structure originale
  765.   else if (opt->savename_type%100==0) { 
  766.     /* recopier www.. */
  767.     if (opt->savename_type!=100) {  
  768.       if (((opt->savename_type/1000)%2)==0) {    // >1000 signifie "pas de www/"
  769.         if (strcmp(adr_complete,"file://")==0) {
  770.           //## if (*adr==lOCAL_CHAR) {
  771.           if (opt->savename_83 != 1)  // noms longs
  772.             strcat(save,"localhost");
  773.           else
  774.             strcat(save,"local");
  775.         } else {
  776.           // adresse url
  777.           if (!opt->savename_83) {  // noms longs (et pas de .)
  778.             strcat(save,print_adr);
  779.           } else {  // noms 8-3
  780.             if (strlen(print_adr)>4) {
  781.               if (strfield(print_adr,"www."))
  782.                 strncat(save,print_adr+4,max_char);
  783.               else
  784.                 strncat(save,print_adr,8);
  785.             } else strncat(save,print_adr,max_char);
  786.           }
  787.         }
  788.         if (*fil!='/') strcat(save,"/");
  789.       }
  790.     }
  791.   
  792. #if HTS_CASSE==0
  793.     hts_lowcase(save);
  794. #endif  
  795.         
  796.     /*
  797.     // ne sert α rien car a dΘja ΘtΘ filtrΘ normalement
  798.     if ((*fil=='.') && (*(fil+1)=='/'))          // ./index.html ** //
  799.       url_savename_addstr(save,fil+2);
  800.     else                                               // index.html ou /index.html
  801.       url_savename_addstr(save,fil);
  802.     if (save[strlen(save)-1]=='/') 
  803.       strcat(save,DEFAULT_HTML);     // nommer page par dΘfaut!!
  804. */
  805.  
  806.     /* add name */
  807.     ADD_STANDARD_PATH;
  808.     ADD_STANDARD_NAME(0);
  809.  
  810.   }
  811.   //
  812.   // Structure html/image
  813.   else {    
  814.     // dossier "web" ou "www.xxx" ?
  815.     if (((opt->savename_type/1000)%2)==0) {    // >1000 signifie "pas de www/"
  816.       if ((opt->savename_type/100)%2) {
  817.         if (strcmp(adr_complete,"file://")==0) {
  818.         //## if (*adr==lOCAL_CHAR) {
  819.           if (opt->savename_83 != 1)  // noms longs
  820.             strcat(save,"localhost/");
  821.           else
  822.             strcat(save,"local/");
  823.         } else {
  824.           // adresse url
  825.           if (!opt->savename_83) {  // noms longs
  826.             strcat(save,print_adr); strcat(save,"/");
  827.           } else {  // noms 8-3
  828.             if (strlen(print_adr)>4) {
  829.               if (strfield(print_adr,"www."))
  830.                 strncat(save,print_adr+4,max_char);
  831.               else
  832.                 strncat(save,print_adr,max_char);
  833.               strcat(save,"/");
  834.             } else { 
  835.               strncat(save,print_adr,max_char); strcat(save,"/");
  836.             }
  837.           }
  838.         }
  839.       } else {
  840.         strcat(save,"web/");    // rΘpertoire gΘnΘral
  841.       }
  842.     } 
  843.  
  844.     // si un html α coup s√r
  845.     if ( (ext_chg!=0) ? (ishtml_ext(ext)==1) : (ishtml(fil)==1) ) {
  846.       if (opt->savename_type%100==2) {  // html/
  847.         strcat(save,"html/");
  848.       }
  849.     } else {
  850.       if ((opt->savename_type%100==1) || (opt->savename_type%100==2)) {  // html & images
  851.         strcat(save,"images/");
  852.       }
  853.     }
  854.     
  855.     switch (opt->savename_type%100) {
  856.     case 4: case 5: {           // sΘparer par types
  857.       char* a=fil+strlen(fil)-1;
  858.       // passer structures
  859.       while(( a > fil) && (*a != '/') && (*a != '\\')) a--;      
  860.       if ((*a=='/') || (*a=='\\')) a++;
  861.  
  862.       // html?
  863.       if ( (ext_chg!=0) ? (ishtml_ext(ext)==1) : (ishtml(fil)==1) ) {
  864.         if (opt->savename_type%100==5)
  865.           strcat(save,"html/");
  866.       } else {
  867.         char* a=fil+strlen(fil)-1;
  868.         while(( a> fil) && (*a != '/') && (*a != '.')) a--;      
  869.         if (*a!='.')
  870.           strcat(save,"other");
  871.         else
  872.           strcat(save,a+1);
  873.         strcat(save,"/");
  874.       }
  875.       /*strcat(save,a);*/
  876.       /* add name */
  877.       ADD_STANDARD_NAME(0);
  878.             }
  879.       break;
  880.     case 99: {                  // 'codΘ' .. c'est un gadget
  881.       int i;
  882.       int j;
  883.       char* a;
  884.       char C[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
  885.       int L;
  886.       // pseudo-CRC sur fil et adr pour initialiser gΘnΘrateur alΘatoire..
  887.       unsigned int s=0;
  888.       L=strlen(C);
  889.       for(i=0;i<(int) strlen(fil_complete);i++) {
  890.         s+=(unsigned int) fil_complete[i];
  891.       }
  892.       for(i=0;i<(int) strlen(adr_complete);i++) {
  893.         s+=(unsigned int) adr_complete[i];
  894.       }
  895.       srand(s);
  896.       
  897.       j=strlen(save);
  898.       for(i=0;i<8;i++) {
  899.         char c=C[(rand()%L)];
  900.         save[i+j]=c;
  901.       }
  902.       save[i+j]='\0';
  903.       // ajouter extension
  904.       a=fil+strlen(fil)-1;
  905.       while(( a > fil) && (*a != '/') && (*a != '.')) a--;
  906.       if (*a=='.') {
  907.         strcat(save,a);    // ajouter
  908.       }
  909.              } 
  910.       break;
  911.     default: {   // noms sans les noms des rΘpertoires
  912.       // ne garder que le nom, pas la structure
  913.       /*
  914.       char* a=fil+strlen(fil)-1;
  915.       while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) a--;      
  916.       if ((*a=='/') || (*a=='\\')) a++;
  917.       strcat(save,a);
  918.       */
  919.  
  920.       /* add name */
  921.       ADD_STANDARD_NAME(0);
  922.             }
  923.       break;
  924.     }
  925.  
  926. #if HTS_CASSE==0
  927.     hts_lowcase(save);
  928. #endif  
  929.  
  930.     if (save[strlen(save)-1]=='/') 
  931.       strcat(save,DEFAULT_HTML);     // nommer page par dΘfaut!!
  932.   }
  933.  
  934.  
  935.   // vΘrifier qu'on ne doit pas forcer l'extension
  936.   // par exemple, asp sera sauvΘ en html, cgi en html ou gif, xbm etc.. selon les cas
  937.   /*if (ext_chg) {
  938.     char* a=save+strlen(save)-1;
  939.     while(((int) a>(int) save) && (*a!='.') && (*a!='/')) a--;
  940.     if (*a=='.') *a='\0';  // couper
  941.     // recopier extension
  942.     strcat(save,".");
  943.     strcat(save,ext);    // copier ext
  944.   }*/
  945.   // de mΩme en cas de manque d'extension on en place une de maniΦre forcΘe..
  946.   // cela Θvite les /chez/toto et les /chez/toto/index.html incompatibles
  947.   if (opt->savename_type != -1) {
  948.     char* a=save+strlen(save)-1;
  949.     while(( a > save) && (*a!='.') && (*a!='/')) a--;
  950.     if (*a!='.') {   // agh pas de point
  951.       //strcat(save,".none");                 // a Θviter
  952.       strcat(save,".html");                   // prΘfΘrable!
  953.       if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  954.         fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Default HTML type set for %s%s"LF,adr_complete,fil_complete);
  955.         test_flush;
  956.       }
  957.     }
  958.   }
  959.  
  960.   // effacer pass au besoin pour les autentifications
  961.   // (plus la peine : masquΘ au dΘbut)
  962. /*
  963.   {
  964.     char* a=jump_identification(save);
  965.     if (a!=save) {
  966.       char tempo[HTS_URLMAXSIZE*2];
  967.       char *b;
  968.       tempo[0]='\0';
  969.       strcpy(tempo,"[");
  970.       b=strchr(save,':');
  971.       if (!b) b=strchr(save,'@');
  972.       if (b)
  973.         strncat(tempo,save,(int) b-(int) a);
  974.       strcat(tempo,"]");
  975.       strcat(tempo,a);
  976.       strcpy(save,a);
  977.     }
  978.   }
  979. */
  980.  
  981.   // Θviter les / au dΘbut (cause: N100)
  982.   if (save[0]=='/') {
  983.     char tempo[HTS_URLMAXSIZE*2];
  984.     strcpy(tempo,save+1);
  985.     strcpy(save,tempo);
  986.   }
  987.  
  988.   // changer les ~,:,",*,? en _ pour sauver sur disque
  989.   hts_replace(save,'~','_');  // interdit sous unix (~foo)
  990.   //
  991.   hts_replace(save,'\\','_');
  992.   hts_replace(save,':','_');  // interdit sous windows
  993.   hts_replace(save,'*','_');  // interdit sous windows
  994.   hts_replace(save,'?','_');  // doit pas arriver!!
  995.   hts_replace(save,'\"','_');  // interdit sous windows
  996.   hts_replace(save,'<','_');  // interdit sous windows
  997.   hts_replace(save,'>','_');  // interdit sous windows
  998.   hts_replace(save,'|','_');  // interdit sous windows
  999.   //
  1000.   hts_replace(save,'@','_');
  1001.   //
  1002.   { // Θliminer les // (comme ftp://)
  1003.     char* a;
  1004.     while( (a=strstr(save,"//")) ) *a='_';
  1005.     // Eliminer chars spΘciaux
  1006.     a=save -1 ;
  1007.     while(*(++a))
  1008.       if ( ((unsigned char)(*a) <= 31)
  1009.           || ((unsigned char)(*a) == 127) )
  1010.         *a='_';
  1011.   }
  1012.  
  1013.    
  1014. #if HTS_OVERRIDE_DOS_FOLDERS
  1015.   /* Replace /foo/nul/bar by /foo/nul-/bar */
  1016.   {
  1017.     int i=0;
  1018.     while(hts_tbdev[i][0]) {
  1019.       char* a=save;
  1020.       while((a=strstr(a,hts_tbdev[i]))) {
  1021.         switch ( (int) a[strlen(hts_tbdev[i])] ) {
  1022.         case '\0':
  1023.         case '/':  {
  1024.           char tempo[HTS_URLMAXSIZE*2]; tempo[0]='\0';
  1025.           strncat(tempo,save,(int) (a - save) + strlen(hts_tbdev[i]));
  1026.           strcat(tempo,"-");
  1027.           strcat(tempo,a+strlen(hts_tbdev[i]));
  1028.           strcpy(save,tempo);
  1029.                    }
  1030.           break;
  1031.         }
  1032.         a+=strlen(hts_tbdev[i]);
  1033.       }
  1034.       i++;
  1035.     }
  1036.   }
  1037. #endif
  1038.  
  1039.   // conversion 8-3 .. y compris pour les rΘpertoires
  1040.   if (opt->savename_83) {
  1041.     char n83[HTS_URLMAXSIZE*2];
  1042.     long_to_83(opt->savename_83,n83,save);
  1043.     strcpy(save,n83);
  1044.   }
  1045.  
  1046.  
  1047.   /* ensure that there is no ../ (potential vulnerability) */
  1048.   fil_simplifie(save);
  1049.  
  1050. #if HTS_ANALYSTE
  1051.   {
  1052.     hts_htmlcheck_savename(adr_complete,fil_complete,referer_adr,referer_fil,save);
  1053.     if ( (opt->debug>0) && (opt->log!=NULL) ) {
  1054.       fspc(opt->log,"info"); fprintf(opt->log,"engine: save-name: local name: %s%s -> %s"LF,adr,fil,save);
  1055.       test_flush;
  1056.     }
  1057.   }
  1058. #endif
  1059.  
  1060.   // chemin primaire Θventuel A METTRE AVANT
  1061.   if (strnotempty(opt->path_html)) {
  1062.     char tempo[HTS_URLMAXSIZE*2];
  1063.     strcpy(tempo,opt->path_html);
  1064.     strcat(tempo,save);
  1065.     strcpy(save,tempo);
  1066.   }
  1067.  
  1068.  
  1069.   // vΘrifier que le nom n'est pas dΘja pris...
  1070.   if (liens!=NULL) { 
  1071.     int nom_ok;
  1072.     do {
  1073.       int i;
  1074.       int len;
  1075.       len=strlen(save);    // taille
  1076.       //
  1077.       nom_ok=1;  // α priori bon
  1078.       // on part de la fin pour optimiser, plus les opti de taille pour aller encore plus vite..
  1079. #if DEBUG_SAVENAME
  1080. printf("\nStart search\n");
  1081. #endif
  1082.  
  1083. #if HTS_HASH
  1084.       i=hash_read(hash,save,"",0);      // lecture type 0 (sav)
  1085.       if (i>=0)
  1086. #else
  1087.       for(i=lien_tot-1;i>=0;i--) {
  1088. #if DEBUG_SAVENAME
  1089. printf("%cParse: %d",13,i);
  1090. #endif
  1091.         
  1092.         if (liens[i]->sav_len==len) {    // mΩme taille de chaεne          
  1093. #if HTS_CASSE
  1094.           if (strcmp(liens[i]->sav,save)==0)    // existe dΘja
  1095. #else
  1096.           if (strfield2(liens[i]->sav,save))    // un tel nom existe dΘja
  1097. #endif
  1098. #endif
  1099.           {
  1100. #if HTS_CASSE
  1101.             if ((strcmp(liens[i]->adr,adr)==0) && (strcmp(liens[i]->fil,fil_complete)==0))
  1102. #else
  1103.             if ((strfield2(liens[i]->adr,adr)) && (strfield2(liens[i]->fil,fil_complete)))
  1104. #endif
  1105.             {    // ok c'est le mΩme lien, adresse dΘja dΘfinie
  1106.               //printf("Ok, %s\n",save);
  1107.               //i=lien_tot;    // sortir
  1108.               i=0;
  1109. #if DEBUG_SAVENAME
  1110. printf("\nOK ALREADY DEFINED\n",13,i);
  1111. #endif
  1112.             } else {  // utilisΘ par un AUTRE, changer de nom
  1113.               char tempo[HTS_URLMAXSIZE*2];
  1114.               char* a=save+strlen(save)-1;
  1115.               char* b;
  1116.               int n=2;       
  1117.               tempo[0]='\0';
  1118.  
  1119. #if DEBUG_SAVENAME
  1120. printf("\nWRONG CASE UNMATCH : \n%s\n%s, REDEFINE\n",liens[i]->fil,fil_complete);
  1121. #endif
  1122.               nom_ok=0;
  1123.               i=0;
  1124.               
  1125.               while(( a > save) && (*a!='.') && (*a!='\\') && (*a!='/')) a--;
  1126.               if (*a=='.')
  1127.                 strncat(tempo,save,(int) (a - save));
  1128.               else
  1129.                 strcat(tempo,save);
  1130.               
  1131.               // tester la prΘsence d'un -xx (ex: index-2.html -> index-3.html)
  1132.               b=tempo+strlen(tempo)-1;
  1133.               while (isdigit((unsigned char)*b)) b--;
  1134.               if (*b=='-') {
  1135.                 sscanf(b+1,"%d",&n);
  1136.                 *b='\0';    // couper
  1137.                 n++;  // plus un
  1138.               }
  1139.               
  1140.               // en plus il faut gΘrer le 8-3 .. pas facile le client
  1141.               if (opt->savename_83) {
  1142.                 int max;
  1143.                 char* a=tempo+strlen(tempo)-1;
  1144.                 while(( a > tempo) && (*a!='/')) a--;
  1145.                 if (*a=='/') a++;
  1146.                 max=max_char-1-nombre_digit(n);
  1147.                 if ((int) strlen(a)>max)
  1148.                   *(a+max)='\0';  // couper sinon il n'y aura pas la place!
  1149.               }
  1150.               
  1151.               // ajouter -xx (ex: index.html -> index-2.html)
  1152.               sprintf(tempo+strlen(tempo),"-%d",n);
  1153.               
  1154.               // ajouter extension
  1155.               if (*a=='.')
  1156.                 strcat(tempo,a);
  1157.               
  1158.               strcpy(save,tempo);
  1159.               
  1160.               //printf("switched: %s\n",save);
  1161.               
  1162.             }  // if
  1163. #if HTS_HASH
  1164.           }
  1165. #else
  1166.           }  // if
  1167.         }  // if sav_len
  1168.       }  // for
  1169. #endif
  1170. #if DEBUG_SAVENAME
  1171. printf("\nEnd search, %s\n",fil_complete);
  1172. #endif
  1173.     } while(!nom_ok);
  1174.     
  1175.   }
  1176.   
  1177.   //printf("'%s' %s %s\n",save,adr,fil);
  1178.       
  1179.   return 0;
  1180. }
  1181.  
  1182. /* nom avec md5 urilisΘ partout */
  1183. void standard_name(char* b,char* dot_pos,char* nom_pos,char* fil_complete,int short_ver) {
  1184.   b[0]='\0';
  1185.   /* Nom */
  1186.   if (dot_pos) {
  1187.     if (!short_ver)    // Noms longs
  1188.       strncat(b,nom_pos,(int) (dot_pos - nom_pos));
  1189.     else
  1190.       strncat(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  1191.   } else {
  1192.     if (!short_ver)    // Noms longs
  1193.       strcat(b,nom_pos);
  1194.     else
  1195.       strncat(b,nom_pos,8);
  1196.   }
  1197.   /* MD5 - 16 bits */
  1198.   strncat(b,url_md5(fil_complete),4);
  1199.   /* Ext */
  1200.   if (dot_pos) {
  1201.     strcat(b,".");
  1202.     if (!short_ver)    // Noms longs
  1203.       strcat(b,dot_pos+1);
  1204.     else
  1205.       strncat(b,dot_pos+1,3);
  1206.   } else {
  1207.     if (!short_ver)    // Noms longs
  1208.       strcat(b,DEFAULT_EXT);    // pas de..
  1209.     else
  1210.       strcat(b,DEFAULT_EXT_SHORT);    // pas de..
  1211.   }
  1212. }
  1213.  
  1214.  
  1215. /* Petit md5 */
  1216. char* url_md5(char* fil_complete) {
  1217.   char* digest;
  1218.   char* a;
  1219.   NOSTATIC_RESERVE(digest, char, 32+2);
  1220.   digest[0]='\0';
  1221.   a=strchr(fil_complete,'?');
  1222.   if (a) {
  1223.     if (strlen(a)) {
  1224.       char buff[HTS_URLMAXSIZE*2];
  1225.       a++;
  1226.       digest[0]=buff[0]='\0';
  1227.       strcat(buff,a);         /* query string MD5 */
  1228.       domd5mem(buff,strlen(buff),digest,1,0);
  1229.     }
  1230.   }
  1231.   return digest;
  1232. }
  1233.  
  1234. // interne α url_savename: ajoute une chaεne α une autre avec \ -> /
  1235. void url_savename_addstr(char* d,char* s) {
  1236.   int i=strlen(d);
  1237.   while(*s) {
  1238.     if (*s=='\\')  // remplacer \ par des /
  1239.       d[i++]='/';
  1240.     else
  1241.       d[i++]=*s;
  1242.     s++;
  1243.   }
  1244.   d[i]='\0';
  1245. }
  1246.  
  1247. #undef test_flush
  1248.